package com.hulk.dryad.web.controller;

import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSort;
import com.hulk.dryad.common.annotation.Idempotent;
import com.hulk.dryad.common.annotation.PrintlnLog;
import com.hulk.dryad.common.annotation.RespData;
import com.hulk.dryad.common.component.R;
import com.hulk.dryad.common.constant.SecurityConstants;
import com.hulk.dryad.common.util.JacksonUtil;
import com.xkcoding.justauth.AuthRequestFactory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.security.Principal;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;


/**
 * @author lqx
 */

@Api(value = " OAuth2", tags = "社交登录")
@ApiSort(2)
@Slf4j
@RestController
@RequestMapping("/oauth")
@RequiredArgsConstructor()
public class OAuth2Controller {

    private final AuthRequestFactory factory;


    @ApiOperation(value = "list", notes = "授权列表")
    @GetMapping("/list")
    @RespData
    public List<String> list() {
        return factory.oauthList();
    }

    @SneakyThrows
    @ApiOperation(value = "logintype", notes = "登录")
    @ApiOperationSupport(order = 0)
	@PrintlnLog
	@Idempotent
    @GetMapping("/login/{type}")
    public void login(@PathVariable String type, HttpServletResponse response) {
        AuthRequest authRequest = factory.get(type);
        response.sendRedirect(authRequest.authorize(AuthStateUtils.createState()));
    }
    

	@ApiOperation(value = "callback", notes = "回调")
	@ApiOperationSupport(order = 2)
	@PrintlnLog
	@RequestMapping("/{type}/callback")
	@RespData
	public AuthResponse callback(@PathVariable String type, AuthCallback callback) {
		AuthRequest authRequest = factory.get(type);
		AuthResponse response = authRequest.login(callback);
		log.info("【response】= {}", JacksonUtil.toJson(response));
		return response;
	}



    @Autowired
    private TokenEndpoint tokenEndpoint;


    /**
     * 自定义oauth2格式返回
     */
    @GetMapping("/token")
    public R getAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        return customReturn(tokenEndpoint.getAccessToken(principal, parameters).getBody());
    }


    /**
     * 自定义oauth2格式返回
     */
    @PostMapping("/token")
    public R postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        return customReturn(tokenEndpoint.postAccessToken(principal, parameters).getBody());
    }

    /**
     * 自定义格式返回
     */
    private R customReturn(OAuth2AccessToken accessToken) {
        DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) accessToken;
        Map<String, Object> data = new LinkedHashMap(token.getAdditionalInformation());
        data.put(SecurityConstants.ACCESS_TOKEN, token.getValue());
        if (token.getRefreshToken() != null) {
            data.put(SecurityConstants.REFRESH_TOKEN, token.getRefreshToken().getValue());
        }
        int expireIn = token.getExpiresIn();
        data.put(SecurityConstants.EXPIRES_IN, expireIn);
        data.put(SecurityConstants.TOKEN_TYPE, token.getTokenType());
        if (null != token.getScope()) {
            data.put(SecurityConstants.SCOPE, token.getScope().toArray()[0]);
        }
        R result = R.ok(data);
        log.info("OAuth2登陆自定义格式返回:[{}]", result);
        return result;
    }


}